#include <mockcpp/mockcpp.hpp>
#include <testngpp/testngpp.hpp>
#include <math.h>
#include <limits>
#include <Rectangle.h>

USING_MOCKCPP_NS
USING_TESTNGPP_NS

namespace
{
const float deltaThreshold = std::numeric_limits<float>::epsilon();
}

FIXTURE(Rectangle_isValid)
{
    TEST(should be able to check it is valid when width,height are valid )
    {
        Rectangle rect(2, 3);
        ASSERT_EQ(true, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when width is 0)
    {
        Rectangle rect(0, 3);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when height is 0)
    {
        Rectangle rect(1, 0);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when width is minus)
    {
        Rectangle rect(-1, 3);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when height is minus)
    {
        Rectangle rect(1, -1);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when width is larger than 100)
    {
        Rectangle rect(1, 100.1);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when height is equal to 75)
    {
        Rectangle rect(75, 1);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is invalid when height is larger than 75)
    {
        Rectangle rect(75.1, 1);
        ASSERT_EQ(false, rect.isValid());
    }
    
    TEST(should be able to check it is valid when width is 100)
    {
        Rectangle rect(1, 100.0);
        ASSERT_EQ(true, rect.isValid());
    }
    
    TEST(should be able to check it is valid when height is 74.99)
    {
        Rectangle rect(74.99, 1);
        ASSERT_EQ(true, rect.isValid());
    }
};

FIXTURE(Rectangle_getArea)
{
    TEST(should be able to cal area : 2*3=6)
    {
        Rectangle rect(2,3);
        ASSERT_EQ(6, rect.getArea());
    }
    
    TEST(should be able to calc area : 2.5*3.5=8.75)
    {
        Rectangle rect(2.5,3.5);
        ASSERT_DELTA(8.75, rect.getArea(), deltaThreshold);
    }
    
    TEST(should be able to trunc width and height : 2.502*3.502=8.75)
    {
        Rectangle rect(2.502,3.502);
        ASSERT_DELTA(8.75, rect.getArea(), deltaThreshold);
    }
    
    TEST(should be able to round area when the decimal part smaller than 0.5: 2.532*3.534=8.93)
    {
        Rectangle rect(2.532,3.534);
        ASSERT_DELTA(8.93, rect.getArea(), deltaThreshold);
    }
    
    TEST(should be able to round area when the decimal part more than 0.5: 2.11*3.14=6.63)
    {
        Rectangle rect(2.11,3.14);
        ASSERT_DELTA(6.63, rect.getArea(), deltaThreshold);
    }
    
    TEST(area should be 0 when it is invalid (minus)) 
    {
        Rectangle rect(1, -1);
        ASSERT_EQ(0, rect.getArea());
    }
   
    TEST(area should be 0 when it is invalid (larger than 100)) 
    {
        Rectangle rect(105, 2);
        ASSERT_EQ(0, rect.getArea());
    }

};

FIXTURE(Rectangle_getPerimeter)
{
    TEST(should be able to calc perimeter: 2*(2.1+3.1)=10.4)
    {
        Rectangle rect(2.1,3.1);
        ASSERT_DELTA(10.4, rect.getPerimeter(), deltaThreshold);
    } 
    
    TEST(should be able to calc perimeter: 2*(6.333+3.555)=19.76)
    {
        Rectangle rect(6.333,3.555);
        ASSERT_DELTA(19.76, rect.getPerimeter(), deltaThreshold);
    } 
      
    TEST(should be able to calc perimeter: 2*(2+3)=10)
    {
        Rectangle rect(2,3);
        ASSERT_EQ(10, rect.getPerimeter());
    }    
    
    TEST(perimeter should be 0 when it is invalid (minus)) 
    {
        Rectangle rect(1, -1);
        ASSERT_EQ(0, rect.getPerimeter());
    }
    
    TEST(perimeter should be 0 when it is invalid (larger than 100)) 
    {
        Rectangle rect(105, 2);
        ASSERT_EQ(0, rect.getPerimeter());
    }
};


FIXTURE(Rectangle_setHeight)
{
    TEST(set a invalid new height, the area should be same to before (before is valid))
    {
        Rectangle rect(10, 2);
        ASSERT_EQ(20, rect.getArea());
        
        rect.setHeight(80);
        ASSERT_EQ(20, rect.getArea());
    }
    
    TEST(set a invalid new height, the area should be same to before (before is invalid))
    {
        Rectangle rect(0, 2);
        ASSERT_EQ(0, rect.getArea());
        
        rect.setHeight(80);
        ASSERT_EQ(0, rect.getArea());
    }
    
    TEST(set a valid new height, the area should be changed)
    {
        Rectangle rect(10, 2);   
        ASSERT_EQ(20, rect.getArea());
             
        rect.setHeight(50);
        ASSERT_EQ(100, rect.getArea());
    }   
};

FIXTURE(Rectangle_setWidth)
{
    TEST(set a invalid new width, the area should be same to before (before is valid))
    {
        Rectangle rect(2, 10);
        ASSERT_EQ(20, rect.getArea());
        
        rect.setWidth(110);
        ASSERT_EQ(20, rect.getArea());
    }
    
    TEST(set a invalid new width, the area should be same to before (before is invalid))
    {
        Rectangle rect(0, 10);
        ASSERT_EQ(0, rect.getArea());
        
        rect.setWidth(110);
        ASSERT_EQ(0, rect.getArea());
    }
    
    TEST(set a valid new width, the area should be changed)
    {
        Rectangle rect(2, 10);   
        ASSERT_EQ(20, rect.getArea());
             
        rect.setWidth(50);
        ASSERT_EQ(100, rect.getArea());
    }
};
